// MyApplication.cpp : Defines the entry point for the console application.
//


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
//#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <list>
#include <curl/curl.h>
#include <unistd.h>
#include <fuse.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <libxml/parser.h>
#include <libxml/tree.h>


using namespace std;

#include "Account.cpp"
#include "AzureOperations.cpp"




typedef struct curl_slist* CURLHEADER;
typedef std::list< pair<string,string> > KEYVALUELIST;
CURLHEADER headers = NULL;
CURL *curl;
CURLcode res;
static const EVP_MD* evp_md = EVP_sha256();
std::wstring str2;
unsigned char* decodedKey = NULL;
int decodedKeySize = 0;

void initCurlForNewOperation()
{
	curl_slist_free_all(headers);
	headers = NULL;
	curl_easy_reset(curl);
}

/**
 * determine the value of a base64 encoding character
 *
 * @param base64char the character of which the value is searched
 * @return the value in case of success (0-63), -1 on failure
 */  
int _base64_char_value(char base64char)
 {
    if (base64char >= 'A' && base64char <= 'Z')
 return base64char-'A';
    if (base64char >= 'a' && base64char <= 'z')
 return base64char-'a'+26;
    if (base64char >= '0' && base64char <= '9')
 return base64char-'0'+2*26;
    if (base64char == '+')
 return 2*26+10;
    if (base64char == '/')
 return 2*26+11;
    return -1;
}

/**
 * decode a 4 char base64 encoded byte triple
 *
 * @param quadruple the 4 characters that should be decoded
 * @param result the decoded data
 * @return lenth of the result (1, 2 or 3), 0 on failure
 */  
int _base64_decode_triple(char* quadruple, unsigned char *result)
 {
    int i, triple_value, bytes_to_decode = 3, only_equals_yet = 1;
    int char_value[4];

    for (i=0; i<4; i++)
 char_value[i] = _base64_char_value(quadruple[i]);

    /* check if the characters are valid */
    for (i=3; i>=0; i--)
    {
 if (char_value[i]<0)
 {
     if (only_equals_yet && quadruple[i]=='=')
     {
  /* we will ignore this character anyway, make it something
   * that does not break our calculations */
  char_value[i]=0;
  bytes_to_decode--;
  continue;
     }
     return 0;
 }
 /* after we got a real character, no other '=' are allowed anymore */
 only_equals_yet = 0;
    }

    /* if we got "====" as input, bytes_to_decode is -1 */
   if (bytes_to_decode < 0)
 bytes_to_decode = 0;

    /* make one big value out of the partial values */
    triple_value = char_value[0];
    triple_value *= 64;
    triple_value += char_value[1];
    triple_value *= 64;
    triple_value += char_value[2];
    triple_value *= 64;
    triple_value += char_value[3];

    /* break the big value into bytes */
    for (i=bytes_to_decode; i<3; i++)
 triple_value /= 256;
    for (i=bytes_to_decode-1; i>=0; i--)
    {
 result[i] = triple_value%256;
 triple_value /= 256;
    }

    return bytes_to_decode;
} 

/**
 * decode base64 encoded data
 *
 * @param source the encoded data (zero terminated)
 * @param target pointer to the target buffer
 * @param targetlen length of the target buffer
 * @return length of converted data on success, -1 otherwise
 */  
size_t base64_decode(char *source, unsigned char *target, size_t targetlen)
 {
    char *src, *tmpptr;
    char quadruple[4], tmpresult[3];
    int i, tmplen = 3;
    size_t converted = 0;

    
    src = (char *)malloc(strlen(source)+5);
    if (src == NULL)
 return -1;
    strcpy(src, source);
    strcat(src, "====");
    tmpptr = src;

    
    while (tmplen == 3)
    {
 
 for (i=0; i<4; i++)
 {
    
     while (*tmpptr != '=' && _base64_char_value(*tmpptr)<0)
  tmpptr++;

     quadruple[i] = *(tmpptr++);
 }

 
 tmplen = _base64_decode_triple((char*)quadruple, (unsigned char*)tmpresult);

 
 if (targetlen < tmplen) {
     free(src);
     return -1;
 }

 
 memcpy(target, tmpresult, tmplen);
 target += tmplen;
 targetlen -= tmplen;
 converted += tmplen;
    }

    free(src);
    return converted;
} 



/*std::ostream& operator << (std::ostream& s,const CURLHEADER& h)
{
	CURLHEADER temp = h;
	while(temp != NULL){
		s << temp -> data << "------";
		temp = temp -> next;
	}
	return s;
}*/

CURLHEADER buildHeaders(const KEYVALUELIST& m)
{
	for(KEYVALUELIST::const_iterator it = m.begin();it != m.end();it++){
		string tempheader = it->first;		
		tempheader = tempheader.append(":");
		tempheader = tempheader.append(" ");
		tempheader = tempheader.append(it ->second);//key: value
		headers = curl_slist_append(headers,tempheader.c_str());
	}
	return headers;
}

string get_date() 
{
	//return "Wed, 18 Nov 2009 19:36:22 GMT";
	char buf[100];
	time_t t = time(NULL);
	strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
	return buf;
}

/*
char *base64(const char *input, int length)
{
  BIO *bmem, *b64;
  BUF_MEM *bptr;

  b64 = BIO_new(BIO_f_base64());
  bmem = BIO_new(BIO_s_mem());
  b64 = BIO_push(b64, bmem);
  BIO_write(b64, input, length);
  BIO_flush(b64);
  BIO_get_mem_ptr(b64, &bptr);

  char *buff = (char *)malloc(bptr->length);
  memcpy(buff, bptr->data, bptr->length-1);
  buff[bptr->length-1] = 0;

  BIO_free_all(b64);

  return buff;
}
*/

void printByteArray(unsigned char* x,int len)
{
	cout << "\n";
	for(int i = 0;i < len;i++)
		cout << (unsigned)(x[i]) << ",";
	cout << "\n";
}

unsigned char * decode(std::string x,int& outlen)
{
	//const byte* schars = ((const byte*)(x.c_str())); //Commented this on 12/08/09. Throws namespace errors otherwise. 
	char* pin = NULL;
	pin = (char*)x.c_str(); 

	unsigned char* pout = (unsigned char*)malloc(sizeof(char) * (x.size() + 100));
	//cout << "just b4 base64_decode " << x << "---" << outlen;
	outlen = base64_decode(pin,pout,(sizeof(char)* (x.size() + 100)));
	cout << "setting outlen as " << outlen;
	//cout << "\nAfter decoding : ";
	//printByteArray((unsigned char*)pout,outLen);
	return pout;

}

string signHeader(const string& toSign,const string& secKey)
{
	cout << "------------toSign--------" << toSign;
	string signedHeader;// = toSign;
	unsigned char* signatureByteForm = (unsigned char*)toSign.c_str();
	int n = toSign.size();

	int keyLen = 0;
	unsigned char* key;
	key = decode(secKey,keyLen);

	unsigned int md_len;
    unsigned char md[EVP_MAX_MD_SIZE];

	HMAC(evp_md,key, keyLen, signatureByteForm, n, md, &md_len);

	BIO* b64 = BIO_new(BIO_f_base64());
    BIO* bmem = BIO_new(BIO_s_mem());
    b64 = BIO_push(b64, bmem);
    BIO_write(b64, md, md_len);
    BIO_flush(b64);
    BUF_MEM *bptr;
    BIO_get_mem_ptr(b64, &bptr);

    signedHeader.resize(bptr->length - 1);
    memcpy(&signedHeader[0], bptr->data, bptr->length-1);

    BIO_free_all(b64);
    free(key);
	return signedHeader;
}

/*int createContainer(const string& baseURL,const string& accountName,const string& containerName,const string& secKey)
{
	
}

int listContainers(const string& baseURL,const string& accountName,const string& secKey)
{
	
}

int deleteContainer(const string& baseURL,const string& accountName,const string& containerName,const string& secKey)
{
	
}

int createBlob(const string& baseURL,const string& accountName,const string& containerName,const string& blobName,const string& secKey)
{
	
}

int listBlobs(const string& baseURL,const string& accountName,const string& contName,const string& secKey)

{
	
}*/




unsigned char* getUTFBytes(std::string& x,int& len)
{
	unsigned char* a = (unsigned char*)x.c_str();
	int bytelength = x.size();
	str2 = std::wstring(x.length(), L' '); // Make room for characters
	// Copy string to wstring.
	std::copy(x.begin(), x.end(), str2.begin());
	//...
	unsigned char* unidata = a;//(const byte*)str2.data();
	len = bytelength;//str2.size();
	cout << "string : " << x;
	cout << "\nUTF bytes : ";
	for(unsigned int i = 0;i < bytelength;i++) cout << (unsigned)unidata[i] << ",";
	return (unsigned char*)unidata;
}



void getHMAC(unsigned char data[],int datalen,unsigned char key[],int keylen)
{
	cout << "\nBefore encryption : ";
	cout << "\nData : ";
	printByteArray(data,datalen);
	cout << "\nKey : ";
	printByteArray(key,keylen);

	unsigned char md[EVP_MAX_MD_SIZE];
	unsigned int mdlen;


	HMAC(evp_md, key, keylen, (unsigned char*)data, datalen, md, &mdlen);
	cout << "\nAfter encryption : ";
	cout << "\nData : ";
	printByteArray((unsigned char*)md,mdlen);

}

size_t writeCallback(void* data, size_t blockSize, size_t numBlocks, void* userPtr)
{
	string* userString = static_cast<string*>(userPtr);
	(*userString).append(reinterpret_cast<const char*>(data), blockSize*numBlocks);
	return blockSize*numBlocks;
}

size_t read_function(char* data, size_t blockSize, size_t numBlocks, void* userPtr)
{
	char* userString = static_cast<char*>(userPtr);
	strncat(data,userString,numBlocks);
	//(*data).append(reinterpret_cast<const char*>(data), blockSize*numBlocks);
	return blockSize*numBlocks;
}


class Azure : public Account, public AzureOperations
{
	friend class FuseAzure;
public:
	static Azure* azureStorage;
	static bool firstTime;
	//Implementation of AzureOperations
	private:
		Azure()
		{
			//Account("589project",,);
			setAccountName("589project");
			setSeckey("OZdaDECfWigyx9c202Xb/O/XRSGr5n08WfoPhSr7Jpt/D+74YymTcCpVfNYMxyHe7k/ar7xmHuRlXZBFNa4wFQ==");
			setBaseURL("http://589project.blob.core.windows.net");
			/*decodedKey = (unsigned char*)(malloc(sizeof(char) * (secKey.size() + 100)));
			//decodedKeySize = secKey.size() + 100;
			decodedKey = decode(secKey,decodedKey,decodedKeySize);*/
			curl = curl_easy_init();
		}
		Azure(const Azure&);                 // Prevent copy-construction
 	    Azure& operator=(const Azure&);      // Prevent assignment


	public:

 	    static Azure* getInstance();




		/*int doesContainerExis

		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseText);
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
*/
		string getVersion()
		{
			char buf[] = "2009-09-19";
			return buf;
		}

		/*deleteBlob is working fine. No need to touch this function*/
		int deleteBlob(const char* blobpath,string& responseText,long& rescode)
		{
			string strblobpath(blobpath);
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			headersToBeFormed.push_back(std::make_pair("x-ms-version",getVersion()));

			std::stringstream authHeader;

			authHeader << "DELETE\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";
			authHeader << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n";

			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			authHeader << "x-ms-version:" << getVersion() << "\n";//version
			authHeader << "/" << accountName << "/" << blobpath;//Canonicalized Resource
			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));



			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST,"DELETE");//HTTP HEAD operation
			//curl_easy_setopt(curl, CURLOPT_UPLOAD, true);//HTTP PUT operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			curl_easy_setopt(curl,CURLOPT_URL,(baseURL + "/" + strblobpath).c_str()); //perform
			curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
			curl_easy_setopt(curl,CURLOPT_WRITEDATA,&responseText);
			curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,writeCallback);

			res = curl_easy_perform(curl);
			curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&rescode);

			cout << "\nresponse code in copy blob properties for is " << rescode << "\n";
			return 0;

		}


		/*copyBlob works. No need to change anything*/
		int copyBlob(const char* curname,const char* newname,string& responseText,long& rescode)
		{
			string strcurname(curname);
			string strnewname(newname);

			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			headersToBeFormed.push_back(std::make_pair("x-ms-version",getVersion()));

			headersToBeFormed.push_back(std::make_pair("x-ms-copy-source","/" + accountName + "/" + strcurname));
			std::stringstream authHeader;

			authHeader << "PUT\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "0" << "\n";
			authHeader << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n";
			authHeader << "x-ms-copy-source:" << "/" << accountName << "/" << strcurname << "\n";

			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			authHeader << "x-ms-version:" << getVersion() << "\n";//version
			authHeader << "/" << accountName << "/" << newname;//Canonicalized Resource
			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));



			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_UPLOAD, true);//HTTP PUT operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			curl_easy_setopt(curl,CURLOPT_URL,(baseURL + "/" + strnewname).c_str()); //perform
			curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
			curl_easy_setopt(curl,CURLOPT_WRITEDATA,&responseText);
			curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,writeCallback);

			res = curl_easy_perform(curl);
			curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&rescode);

			cout << "\nresponse code in copy blob properties for is " << rescode << "\n";
			return 0;

		}
		virtual int getBlob(const char* blobPath,FILE* fp,long& resCode,string& resptext)
		{
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			//x-ms-version
			//headersToBeFormed.push_back(std::make_pair("x-ms-version",getVersion()));
			std::stringstream authHeader;

			authHeader << "GET\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";//Date optional if using xms-date
			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			//add the xms version header
			//authHeader << "x-ms-version:" << getVersion() << "\n";
			authHeader << "/" << accountName << blobPath;//Canonicalized Resource
			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));


			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST,"GET");//HTTP HEAD operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			curl_easy_setopt(curl,CURLOPT_URL,(baseURL + blobPath).c_str()); //perform
			//curl_easy_setopt(curl,CURLOPT_FILE,fp);
			//curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
			curl_easy_setopt(curl,CURLOPT_WRITEDATA,fp);
			//curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,writeCallback);

			res = curl_easy_perform(curl);
			curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&resCode);
			fflush(fp);
			//fsync(fd);


			cout << "\nresponse code in getblob " << blobPath << " is " << resCode;
			return 0;

		}


		virtual int getContainerProperties(const string& containerName,string& responseText,string& responseHeader,long& resCode)
		{
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			//x-ms-version
			//headersToBeFormed.push_back(std::make_pair("x-ms-version",getVersion()));
			std::stringstream authHeader;

			authHeader << "GET\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";//Date optional if using xms-date
			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			//add the xms version header
			//authHeader << "x-ms-version:" << getVersion() << "\n";
			authHeader << "/" << accountName << "/" << containerName;//Canonicalized Resource
			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));


			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			//curl_easy_setopt(curl, CURLOPT_UPLOAD, true);//HTTP PUT operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			curl_easy_setopt(curl,CURLOPT_URL,(baseURL + "/" + containerName).c_str()); //perform
			curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
			curl_easy_setopt(curl,CURLOPT_WRITEDATA,&responseText);
			curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,writeCallback);

			res = curl_easy_perform(curl);
			curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&resCode);

			cout << "\nresponse code in getcont properties for contname\n " << containerName << " is " << resCode;
			return 0;

		}
		virtual int getBlobProperties(const string& blobPath,string& responseText,string& responseHeader,long& resCode)
		{
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			//x-ms-version
			//headersToBeFormed.push_back(std::make_pair("x-ms-version",getVersion()));
			std::stringstream authHeader;

			authHeader << "GET\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";//Date optional if using xms-date
			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			//add the xms version header
			//authHeader << "x-ms-version:" << getVersion() << "\n";
			authHeader << "/" << accountName << "/" << blobPath;//Canonicalized Resource
			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));


			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST,"GET");//HTTP HEAD operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			curl_easy_setopt(curl,CURLOPT_URL,(baseURL + "/" + blobPath).c_str()); //perform
			curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
			curl_easy_setopt(curl,CURLOPT_WRITEDATA,&responseText);
			curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,writeCallback);

			res = curl_easy_perform(curl);
			curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&resCode);

			cout << "\nresponse code in getblob properties for contname\n " << blobPath << " is " << resCode;
			return 0;

		}



		virtual int createContainer(const string& containerName)
		{
			initCurlForNewOperation();
			cout << "got inside createContainer";
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			std::stringstream authHeader;

			authHeader << "PUT\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";//Date optional if using xms-date
			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			//authHeader << headersToBeFormed["x-ms-date"] << "\n";//date header
			authHeader << "/" << accountName << "/" << containerName;//Canonicalized Resource
			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));


			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			cout << "***********Header sent*******************\n";
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST,"PUT");//HTTP GET operation
			curl_easy_setopt(curl, CURLOPT_UPLOAD, true);//HTTP PUT operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			curl_easy_setopt(curl,CURLOPT_URL,(baseURL + "/" + containerName).c_str()); //perform
			curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0

			/*string responseText;
			string responseHeader;
			curl_easy_setopt(curl,CURLOPT_WRITEDATA,&responseText);
			curl_easy_setopt(curl,CURLOPT_HEADERDATA,&responseHeader);
			curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,writeCallback);*/
			cout << "before curl perform";
			res = curl_easy_perform(curl);
			cout << "after curl perform";

			/*cout << "Response text got is \n" << responseText << "\n";
			cout << "Response header got is \n" << responseHeader << "\n";*/
			return 0;
			//aders.Add("x-ms-date", DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture));

		}



		int listContainers(const char* prefix,string& responseText,long& statusCode)
		{
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			std::stringstream authHeader;

			authHeader << "GET\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";//Date optional if using xms-date
			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			//authHeader << headersToBeFormed["x-ms-date"] << "\n";//date header
			authHeader << "/" << accountName << "/?comp=list"; // << containerName;//Canonicalized Resource

			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			//signedString=signedString.append("/?comp=list");
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));

			//string responseText;
			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			//cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST,"GET");//HTTP GET operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			if(strcmp(prefix,"/") == 0)
				curl_easy_setopt(curl,CURLOPT_URL,(baseURL+ "/"+"?comp=list").c_str()); //perform
			else{
				string prefixparam(prefix);
				curl_easy_setopt(curl,CURLOPT_URL,(baseURL+ "/"+"?comp=list&prefix=" + prefixparam).c_str()); //perform
			}
			curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseText);
			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);

			//curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
			res = curl_easy_perform(curl);
			curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&statusCode);

			return 1;

		}
		virtual int deleteContainer(const string& containerName)
		{
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			std::stringstream authHeader;

			authHeader << "DELETE\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";//Date optional if using xms-date
			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			//authHeader << headersToBeFormed["x-ms-date"] << "\n";//date header
			authHeader << "/" << accountName << "/" << containerName;//Canonicalized Resource
			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));


			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			//cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");//HTTP PUT operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			curl_easy_setopt(curl,CURLOPT_URL,(baseURL + "/" + containerName).c_str()); //perform
			//curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
			res = curl_easy_perform(curl);
			return 1;
			//aders.Add("x-ms-date", DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture));

		}
		//blob related operations
		virtual int createBlob(const string& bpath)
		{
			int fd=-1;
			fd= fileno(tmpfile());
			
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			std::stringstream authHeader;

			authHeader << "PUT\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";//Date optional if using xms-date
			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			//authHeader << headersToBeFormed["x-ms-date"] << "\n";//date header
			authHeader << "/" << accountName << bpath;//Canonicalized Resource
			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));


			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			//cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_UPLOAD, true);//HTTP PUT operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			curl_easy_setopt(curl,CURLOPT_URL,(baseURL + bpath).c_str()); //perform
			curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
			res = curl_easy_perform(curl);
			return 1;
			//aders.Add("x-ms-date", DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture));

		}
		int listBlobs(const char* contName,string& responseText,long& statusCode)
		{
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			std::stringstream authHeader;

			authHeader << "GET\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";//Date optional if using xms-date
			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			//authHeader << headersToBeFormed["x-ms-date"] << "\n";//date header

			authHeader << "/" << accountName << contName << "?comp=list"; // << containerName;//Canonicalized Resource

			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			//signedString=signedString.append("/?comp=list");
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));

			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			//cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST,"GET");//HTTP GET operation
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);

			curl_easy_setopt(curl,CURLOPT_URL,(baseURL+ contName + "?comp=list").c_str()); //perform

			//curl_easy_setopt(curl,CURLOPT_URL,(baseURL+ "/"+ contName + "?comp=list").c_str()); //perform
			curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseText);
			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);


			res = curl_easy_perform(curl);
			curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&statusCode);
			return 0;
			//aders.Add("x-ms-date", DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture));

		}
		
		int getBlob(const char* path,FILE* fp,long& statusCode)
		{
			
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			std::stringstream authHeader;

		int putBlob(const char* blobpath,FILE* fp,long& filesize, long& rescode)
		{
			initCurlForNewOperation();
			KEYVALUELIST headersToBeFormed;
			headersToBeFormed.push_back(std::make_pair("x-ms-date",get_date()));
			std::stringstream authHeader;

			authHeader << "PUT\n";//VERB
			authHeader << "\n";//MD5 (Not Used)
			authHeader << "\n";//Content Type
			authHeader << "\n";//Date optional if using xms-date
			//get the blob type header
			headersToBeFormed.push_back(std::make_pair("x-ms-blob-type","BlockBlob"));
			authHeader << "x-ms-blob-type:" << "BlockBlob" << "\n";
			//get the date header
			for(KEYVALUELIST::const_iterator it = headersToBeFormed.begin();it != headersToBeFormed.end();it++){
				if(it->first == "x-ms-date"){
					authHeader << "x-ms-date:" << it->second << "\n";//date header
					break;
				}
			}
			authHeader << "/" << accountName  << blobpath; // << containerName;//Canonicalized Resource

			string signedString = "SharedKey ";
			signedString = signedString.append(accountName);
			signedString = signedString.append(":");
			signedString = signedString.append(signHeader(authHeader.str(),secKey));
			headersToBeFormed.push_back(std::make_pair("Authorization",signedString));

			//build headers
			CURLHEADER contHeaders = buildHeaders(headersToBeFormed);
			cout << "***********Header sent*******************" <<  contHeaders;
			//set the curl options and invoke curl request
			curl_easy_setopt(curl, CURLOPT_UPLOAD, true); // HTTP PUT
			cout << "\nbefor strlendata";
			curl_easy_setopt(curl, CURLOPT_INFILESIZE, filesize); // Content-Length
			cout << "\nafer strlen datat";
			printf("\nsetting header opt as %d",contHeaders);
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, contHeaders);
			cout << "\n afer setting header opt";
			string bpath(path);
			//curl_easy_setopt(curl,CURLOPT_FILE,fp);
			cout << "\nafte bpath " << bpath;
			curl_easy_setopt(curl,CURLOPT_URL,(baseURL+ bpath).c_str()); //perform
			//curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_function);
			cout << "\nafte readfunction ";
			curl_easy_setopt(curl, CURLOPT_READDATA, fp);
			//cout << "\nafte readata " << data;
			//curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseText);
			//curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);

			cout << "\nbefor easy perform";
			res = curl_easy_perform(curl);
			cout << "\nafter easy perform";
			curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&respCode);
			return 0;
			//aders.Add("x-ms-date", DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture));
		}
};

class FuseAzure
{
public:
	int createFile(const char* path)
	{
		long status;
		string spath(path);

		int ret = Azure::getInstance()->createBlob(spath);


		cout << "return for create file " << ret;
		return ret;
	}
	int openFile(const char* path,FILE* fp)
	{
		long status;
		string resptext;
		int ret = Azure::getInstance()->getBlob(path,fp,status,resptext);
		rewind(fp);
		if(status >= 400){//error codes of 400 are bad -> there is no blob corresponding to this fp. so we need to creat one.
			long filesize = 0;
			Azure::getInstance()->putBlob(path,fp,filesize,status);
			if(status >= 400)
				ret = 1;
		}
		cout << "status for opern file " << ret;
		return ret;
	}
	int closeFile(const char* path,FILE* fp,long filesize)
	{
		long status;
		fflush(fp);
		rewind(fp);
		int ret = Azure::getInstance()->putBlob(path,fp,filesize,status);
		cout << "status for close file " << status;
		return ret;
	}
	int getattrFile(const char* filePath,struct stat* stbuf)
	{
		int retval = 0;
		long respCode;
		string responseHeader,responseText = "\0";
		Azure* azure = Azure::getInstance();
		azure->getBlobProperties(filePath,responseText,responseHeader,respCode);
		memset(stbuf, 0, sizeof(struct stat));
		cout << "response text is " << responseText << "\n" << "response code : " << respCode;
		while(respCode == 202)
			;
		if(respCode == 404){
			stbuf -> st_size = 0;
			stbuf->st_mode = 0;
			retval = 20;
		}
		else{//means no response and hence by API definition, the operation was valid on the container => the container exists
			stbuf->st_nlink = 1;
			stbuf->st_size = responseText.size();
			stbuf->st_mode = S_IFREG|0777;
			retval = 0;
		}
		return retval;
	}
	int getattrDirectory(const char* dirName,struct stat* stbuf)
	{
		int retval = 0;
		long respCode;
		string responseHeader,responseText = "\0";
		Azure* azure = Azure::getInstance();
		azure->getContainerProperties(dirName,responseText,responseHeader,respCode);
		memset(stbuf, 0, sizeof(struct stat));
		while(respCode == 202)
			;
		if(respCode == 404 || responseText.size() > 0){
			stbuf -> st_size = 0;
			stbuf->st_mode = 0;
			retval = 20;
		}
		else{//means no response and hence by API definition, the operation was valid on the container => the container exists
			stbuf->st_nlink = 2;
			stbuf->st_size = 4096;
			stbuf->st_mode = S_IFDIR|0777;
			retval = 0;
		}
		return retval;
	}
	int createDirectory(const char* path)
	{

		return (Azure::getInstance()) ->createContainer(path);
	}

	int parseXML(string data,fuse_fill_dir_t filler,void* buf)
	{
		xmlDocPtr doc = xmlReadMemory(data.c_str(), data.size(), "", NULL, 0);
		xmlNodePtr cur_node = doc -> children->children;
		xmlNodePtr containersNode = NULL;
		while(cur_node != NULL){
			string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
			if(cur_node_name == "Containers"){
				containersNode = cur_node;
				break;
			}
			cur_node = cur_node -> next;
		}

		cur_node = containersNode -> children;
		while(cur_node != NULL){
			string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
			if(cur_node_name == "Container"){
				xmlNodePtr sub_node = cur_node -> children;
				if (sub_node->type == XML_ELEMENT_NODE) {
						string elementName = reinterpret_cast<const char*>(sub_node->name);
						string key;
						if (elementName == "Name"){
							key = reinterpret_cast<const char *>(sub_node->children->content);
							if (filler(buf, key.c_str(), NULL, 0) != 0)
								return -12;//ENOMEM
						}
						//key is the container name
						//log_msg("calling filler with name %s\n", de->d_name);

				}

			}
			cur_node = cur_node -> next;
		}
		return 0;

	}

	int parseBlobXML(string data,fuse_fill_dir_t filler,void* buf)
	{
		xmlDocPtr doc = xmlReadMemory(data.c_str(), data.size(), "", NULL, 0);
		xmlNodePtr cur_node = doc -> children->children;
		xmlNodePtr containersNode = NULL;
		while(cur_node != NULL){
			string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
			if(cur_node_name == "Blobs"){
				containersNode = cur_node;
				break;
			}
			cur_node = cur_node -> next;
		}

		cur_node = containersNode -> children;
		while(cur_node != NULL){
			string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
			if(cur_node_name == "Blob"){
				xmlNodePtr sub_node = cur_node -> children;
				if (sub_node->type == XML_ELEMENT_NODE) {
						string elementName = reinterpret_cast<const char*>(sub_node->name);
						string key;
						if (elementName == "Name"){
							key = reinterpret_cast<const char *>(sub_node->children->content);
							if (filler(buf, key.c_str(), NULL, 0) != 0)
								return -12;//ENOMEM
						}
						//key is the container name
						//log_msg("calling filler with name %s\n", de->d_name);

				}

			}
			cur_node = cur_node -> next;
		}
		return 0;

	}


	int listDirectory(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset)
	{
		string containerXML,blobXML;
		long containerStatus,blobStatus;
		int retval = 0;
		//listcontainers
		if(strcmp(path,"/") == 0){//list only containers for root
			Azure::getInstance()->listContainers(path,containerXML,containerStatus);
			//got the xml,need to parse it now
			//cout << "response data is " << containerXML;
			retval = parseXML(containerXML,filler,buf);
		}
		else{//list only blobs for others
			Azure::getInstance()->listBlobs(path,blobXML,blobStatus);
			cout << "response data is " << blobXML;
			retval = parseBlobXML(blobXML,filler,buf);
		}
		return retval;
		//listblobs
		//return (Azure::getInstance()) ->listContainers();
		//return 0;
	}
	int deleteDirectory(const char* path)
	{
		return (Azure::getInstance())->deleteContainer(path);
	}

	int renameFile(const char* curname,const char* newname)
	{
		//todo - check error handling.
		/*
		 * copy blob
		 * delete old blob
		 */
		string responseText;
		long resCode;
		Azure::getInstance()->copyBlob(curname,newname,responseText,resCode);
		if(resCode == 404 || responseText.size() > 0)//means error
			return 20;//returning no such files or directory by default.
		Azure::getInstance()->deleteBlob(curname,responseText,resCode);
		if(resCode == 404 || responseText.size() > 0)//means error
					return 20;//returning no such files or directory by default.
		return 0;
	}


};

bool Azure::firstTime = true;
Azure* Azure::azureStorage = NULL;
Azure* Azure::getInstance()
{
	if(Azure::firstTime == true){
		Azure::firstTime = false;
		azureStorage = new Azure();
		cout << "new instance";
	}
	return azureStorage;
}



/*int main(int argc,char* argv[])
{
	if(argc > 1){
		cout << "Usage: ./MyApplication \n";
		return 0;
	}
	int userChoice;

	while(true)
	{
		cout << "\n***********************************************\n";
		cout << "Please select one of the following options: \n";
		cout << "  1. Create a new container \n";
		cout << "  2. List existing containers \n";
		cout << "  3. Delete an existing container \n";
		cout << "  4. Create a new blob \n";
		cout << "  5. List existing blobs in a conatiner \n";
		cout << "  6. Exit \n";
		cout << "***********************************************\n\n";

		cin >> userChoice;
		cin.ignore(80,'\n');
	
	switch(userChoice)
	 {
		
		case 1: 
		{
			string newContainer;
			cout << "Enter the name of the container you wish to create \n";
			cin>> newContainer; 
			createContainer(baseURL,account,newContainer,seckey);
			break;
		}
		
		case 2: 
		{
			//string listContainerName;
			//cout << "Enter the name of the container you wish to create \n";
			//cin >> listContainerName; 
			listContainers(baseURL,account,seckey);
			break;
		}
		
		case 3: 
		{
			string delContainer;
			cout << "Enter the name of an existing container you wish to delete \n";
			cin >> delContainer;
			deleteContainer(baseURL,account,delContainer,seckey);
			break;
		}
	 	
		case 4: 
		{
			string blobContName,blobName;
			cout << "Enter the name of an existing container you wish to put your blob into: \n";
			cin >> blobContName;
			cout << "Enter the name of the blob you wish to create: \n";
			cin >> blobName;
			createBlob(baseURL,account,blobContName,blobName,seckey);
			break;
		}
		
	
		case 5: 
		{
			string blobsInContList;
			cout << "Enter the name of an existing container whose blobs are to be listed: \n";
			cin >> blobsInContList;
			listBlobs(baseURL,account,blobsInContList,seckey);
			break;
		}
		
		
		case 6: 
		{
			curl_easy_cleanup(curl);
			exit(1);
			break;
		}
				
		default:
		{
			cout << "Usage: <1-6> \n";
			break;
		}
		
	 }
	
	}
}*/

/*int main(int argc,char* argv[])
{
	//Azure* azure = new Azure();
	struct stat s;
	FuseAzure* fs = new FuseAzure();
	//fs->getattrDirectory(argv[1],&s);
	//curl = curl_easy_init();
	//fs -> createDirectory("venecltest");
	//fs -> createDirectory("venecltest");
	//fs -> listDirectory("venecltest");

	string respText;
	long rescode;
	FILE* fp = fopen("tempfile", "w+");
	fs->openFile("/cganoo/venblob",fp);
	fclose(fp);
	//cout << rescode << "\n" << respText;
	return 0;
}*/
